package com.cww.study.exceptionHandler;




import com.cww.study.event.Event;
import com.cww.study.event.ExceptionListener;
import com.cww.study.exception.ServiceClException;
import com.cww.study.exception.SystemException;
import com.cww.study.utils.RespData;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: myes
 * @description: 全局异常封装成统一格式抛给前端
 * @author: 陈英俊
 * @create: 2021-09-10 09:17
 */
@ConditionalOnProperty(
        prefix = "config",
        name = {"globalDefaultException.open"},
        havingValue = "true",
        matchIfMissing = true
)
@ControllerAdvice // 全局异常处理类
public class GlobalDefultExceptionHandler {

    Logger logger = LoggerFactory.getLogger(GlobalDefultExceptionHandler.class);

    @Value("${config.listener.classpath.exception:}")
    String exceptionListenerPath;

    Event eventSource = new Event();


    @ExceptionHandler({ServiceClException.class})
    @ResponseBody
    public RespData<Object> jsonServiceExceptionHandler(HttpServletRequest req, ServiceClException e) {
        RespData<Object> resp = new RespData();
        resp.setResult(false, e.getCode(), e.getMsg(), "");
        return this.processException(resp, e);
    }

    @ExceptionHandler({SystemException.class})
    @ResponseBody
    public RespData<Object> jsonSystemExceptionHandler(HttpServletRequest req, SystemException e) {
        RespData<Object> resp = new RespData();
        resp.setResult(false, e.getCode(), e.getMsg(), "");
        return this.processException(resp, e);
    }

    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseBody
    public RespData<Object> jsonConstraintViolationException(HttpServletRequest req, ConstraintViolationException e) {
        List<ConstraintViolation<?>> list = new ArrayList(e.getConstraintViolations());
        String msg = null;
        if (!list.isEmpty()) {
            msg = list.get(0).getMessage();
        }

        RespData<Object> resp = new RespData();
        resp.setResult(false, "500", msg, "");
        return this.processException(resp, e);
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public RespData<Object> jsonMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> list = bindingResult.getAllErrors();
        String msg = null;
        if (!list.isEmpty()) {
            msg = list.get(0).getDefaultMessage();
        }

        RespData<Object> resp = new RespData();
        resp.setResult(false, "500", msg, "");
        return this.processException(resp, e);
    }

    @ExceptionHandler({BindException.class})
    @ResponseBody
    public RespData<Object> jsonBindException(HttpServletRequest req, BindException e) {
        List<ObjectError> list = new ArrayList(e.getAllErrors());
        String msg = null;
        if (!list.isEmpty()) {
            msg = list.get(0).getDefaultMessage();
        }

        RespData<Object> resp = new RespData();
        resp.setResult(false, "500", msg, "");
        return this.processException(resp, e);
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public RespData<Object> jsonExceptionHandler(HttpServletRequest req, Exception e) {
        this.logger.error("返回出现异常", e);
        RespData<Object> resp = new RespData();
        resp.setResult(false, "500", "系统内部发生异常", "");
        return this.processException(resp, e);
    }

    private RespData processException(RespData<Object> resp, Exception e) {
        RespData respData = null;
        if (StringUtils.isNotBlank(this.exceptionListenerPath)) {
            try {
                this.eventSource.setExceptionListener
                        (
                                (ExceptionListener) Class.forName(this.exceptionListenerPath)
                                        .newInstance()
                        );
                this.eventSource.processException(e);
                respData = (RespData) this.eventSource.responseException(e);
            } catch (Exception var5) {
                this.logger.error("实例化listener失败", var5.getMessage());
            }
        }

        return respData == null ? resp : respData;
    }
}
